﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;

using Pg.BioMedics.SDR.Entities;
using Pg.BioMedics.SDR.Entities.Codes;
using Pg.BioMedics.SDR.Services;

namespace Pg.BioMedics.SDR.Web.Services
{
    /// <summary>
    /// Service proxy for the business logic indexing service. This proxy is responsible for handling 
    /// requests from the web interface and pushing them to the appropriate either business logic 
    /// service or its interface. This proxy provides strict rules validation before passing
    /// the way to the appropriate service.
    /// </summary>    
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class OperationalWebService : IOperationalWebService
    {
        #region IOperationalWebService Members

        /// <summary>
        /// Registers a new document in the SDR system.
        /// </summary>
        /// <param name="document">Document metadata</param>
        /// <param name="content">Document content</param>
        public void RegisterDocument(Document document, Pg.BioMedics.SDR.Entities.Content content)
        {
            try
            {
                // get author
                HttpContext context = HttpContext.Current;
                string userName = context.User.Identity.Name;
                Person author = ServiceFactory.ManagementService.GetPersonByLogin(userName);

                // register document
                ServiceFactory.IndexingService.RegisterDocument(document, content, author);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not register document", ex);
            }
        }

        /// <summary>
        /// Gets list of documents authored by the user authenticated in the context
        /// </summary>
        /// <returns>List of documents</returns>
        public IList<Document> GetDocuments()
        {
            try
            {
                // get author
                HttpContext context = HttpContext.Current;
                string userName = context.User.Identity.Name;
                Person author = ServiceFactory.ManagementService.GetPersonByLogin(userName);

                // get documents
                return ServiceFactory.IndexingService.GetDocuments(author);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not get documents", ex);
            }
        }

        /// <summary>
        /// Removes document stored by the user
        /// </summary>
        /// <param name="document">Document instance</param>
        public void RemoveDocument(Document document)
        {
            try
            {
                // get author
                HttpContext context = HttpContext.Current;
                string userName = context.User.Identity.Name;
                Person author = ServiceFactory.ManagementService.GetPersonByLogin(userName);

                // chack security rules
                if (!context.User.IsInRole(RoleCodes.Administrator))
                {
                    IList<Document> authoredDocuments = ServiceFactory.IndexingService.GetDocuments(author);
                    if (Contains(authoredDocuments, document))
                        throw new SDRWebServiceException("Permission denied, only document authors or administrators are permitted to remove this document");
                }

                // remove document
                ServiceFactory.IndexingService.RemoveDocument(document, author);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not remove document", ex);
            }
        }

        /// <summary>
        /// Registers a new annotation in the SDR system for the given document
        /// </summary>
        /// <param name="document"></param>
        /// <param name="content"></param>
        public void RegisterAnnotation(Document document, Pg.BioMedics.SDR.Entities.Content content)
        {
            try
            {
                // get author
                HttpContext context = HttpContext.Current;
                string userName = context.User.Identity.Name;
                Person author = ServiceFactory.ManagementService.GetPersonByLogin(userName);

                // register document
                ServiceFactory.IndexingService.RegisterAnnotation(document, content, author);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not register annotation", ex);
            }
        }

        /// <summary>
        /// Executes a text query
        /// </summary>
        /// <param name="query">Textual query</param>
        /// <returns>List of search results</returns>
        public IList<SearchResult> ExecuteTextQuery(string query)
        {
            try
            {
                return ServiceFactory.SearchService.ExecuteTextQuery(query);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not process text query {0}", ex, query);
            }
        }

        /// <summary>
        /// Executes spoken query
        /// </summary>
        /// <param name="spokenQuery">Spoken query content. Must be a wave content with specified parameters</param>
        /// <param name="timeout">Query timeout</param>
        /// <returns>List of results</returns>
        public IList<SearchResult> ExecuteSpokenQuery(byte[] spokenQuery, int timeout)
        {
            try
            {
                return ServiceFactory.SearchService.ExecuteSpokenQuery(spokenQuery, timeout);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not process spoken query", ex);
            }
        }        

        /// <summary>
        /// Gets document related with the given search result
        /// </summary>
        /// <param name="searchResult">Search result</param>
        /// <returns>Document instance</returns>
        public Document GetDocument(SearchResult searchResult)
        {
            try
            {
                return ServiceFactory.SearchService.GetDocument(searchResult);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not get document for search result {0} {1}", ex, searchResult.DocumentId, searchResult.RelevanceScore);
            }
        }

        /// <summary>
        /// Gets content of the given document
        /// </summary>
        /// <param name="document">Document meatada description</param>
        /// <returns>Content assigned to the given document</returns>
        public Pg.BioMedics.SDR.Entities.Content GetContent(Document document)
        {
            try
            {
                // get content
                return ServiceFactory.IndexingService.GetContent(document);
            }
            catch (Exception ex)
            {
                throw new SDRWebServiceException("Could not get for the document", ex, document.Id);
            }
        }

        /// <summary>
        /// Checks service current status
        /// </summary>
        /// <returns>Ok if works fine</returns>
        public string CheckStatus()
        {
            return "ok";
        }

        #endregion

        #region Support methods

        /// <summary>
        /// Checks if given collection contains given document
        /// </summary>
        /// <param name="documents">Documents list</param>
        /// <param name="document">Document </param>
        /// <returns>true if collection contains given document</returns>
        private bool Contains(IList<Document> documents, Document document)
        {
            foreach (Document selectedDocument in documents)
                if (selectedDocument.Id == document.Id)
                    return true;

            return false;
        }

        #endregion
    }
}
